/* -*-  Mode:C; c-basic-offset:8; tab-width:8; indent-tabs-mode:t -*- */
/*
 * Copyright (c) 1999, 2000 Massachusetts Institute of Technology.
 *
 * This software is being provided by the copyright holders under the GNU
 * General Public License, either version 2 or, at your discretion, any later
 * version. (See the file `LICENSE' in the source distribution.)
 *
 * This software is provided "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. The entire risk as
 * to the quality and performance of the program is with you. See the GNU
 * General Public License for more details.
 *
 * The name and trademarks of copyright holders may NOT be used in 
 * advertising or publicity pertaining to the software without specific, 
 * written prior permission. Title to copyright in this software and any 
 * associated documentation will at all times remain with copyright 
 * holders. See the file CMAUTHORS which should have accompanied this software 
 * for a list of all copyright holders. 
 * 
 * Particular files in this distribution may be derived from previously
 * copyrighted software. This copyright applies only to those changes made by
 * the copyright holders listed in the CMAUTHORS file.
 */
/*
 * An implementation of the Congestion Manager (CM) for Linux.
 * Generic CM scheduler.
 */

#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/malloc.h>
#include <net/sock.h>
#include <net/cm.h>
#include <net/cm_debug.h>

extern void udp_ccbufsend(struct sock *);

/*
 * Initialize CM scheduler state when a new CM is instantiated 
 * for this destination (macroflow).  Called by cm_open().
 */
cm_sched_t *cms_init(cm_macroflow_t *mflow)
{
	cm_sched_t *cms;

	CM_DEBUG_ENTER();
	CM_DPRINTF(CM_DEBUG_FLOW_INIT, "cm_debug:  %s on flow %p\n",
		   __FUNCTION__, mflow);
	
	if ((cms = (cm_sched_t *) kmalloc(sizeof(cm_macroflow_t *),GFP_KERNEL))
	    == NULL)
		return NULL;
	cms->mflow = mflow;
	cms->sched_lock = SPIN_LOCK_UNLOCKED;
	return cms;
}

void cms_free(cm_macroflow_t *mf)
{
        CM_DEBUG_ENTER();
	kfree(mf->sched);
}

/*
 * Schedule a transmission of up to 1 MTU by application callback.
 */
void cms_schedule(cm_sched_t *cms)
{
        CM_DEBUG_ENTER();
	/* no two instances of the same scheduler should be running at
           one time */
	spin_lock_bh(&(cms->sched_lock));
	cms->ops.schedule(cms);
	spin_unlock_bh(&(cms->sched_lock));
}

double cms_query_share(cm_sched_t *cms, cm_flow_t *flow)
{
        CM_DEBUG_ENTER();
	return(cms->ops.query_share(cms,flow));
}

void cms_delete_flow(cm_sched_t *cms, cm_flow_t *flow)
{
        CM_DEBUG_ENTER();
	return(cms->ops.delete_flow(cms,flow));
}

void cms_notify(cm_sched_t *cms, cm_flow_t *flow, int nsent)
{
        CM_DEBUG_ENTER();
	cms->ops.notify(cms,flow,nsent);
}
